#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import http.server
import socketserver
import json
import os
import webbrowser
import requests
from datetime import datetime, timedelta
import time
from typing import List, Dict

# 聚合数据API配置
JUHE_FLIGHT_APPKEY = "b0daee5c7cf963ae6458020601583575"

# 城市到IATA机场代码映射
CITY_TO_IATA = {
    '大连': 'DLC', '北京': 'PEK', '上海': 'PVG', '广州': 'CAN',
    '深圳': 'SZX', '成都': 'CTU', '重庆': 'CKG', '西安': 'XIY',
    '武汉': 'WUH', '南京': 'NKG', '杭州': 'HGH', '天津': 'TSN',
    '青岛': 'TAO', '厦门': 'XMN', '长沙': 'CSX', '郑州': 'CGO',
    '合肥': 'HFE', '济南': 'TNA', '福州': 'FOC', '南昌': 'KHN',
    '石家庄': 'SJW', '太原': 'TYN', '呼和浩特': 'HET', '沈阳': 'SHE',
    '长春': 'CGQ', '哈尔滨': 'HRB', '昆明': 'KMG', '贵阳': 'KWE',
    '南宁': 'NNG', '海口': 'HAK', '三亚': 'SYX', '兰州': 'LHW',
    '西宁': 'XNN', '银川': 'INC', '乌鲁木齐': 'URC', '拉萨': 'LXA'
}

# 周边城市映射
NEARBY_CITIES = {
    '大连': ['沈阳', '营口', '丹东', '鞍山'],
    '合肥': ['南京', '武汉', '郑州', '济南'],
    '北京': ['天津', '石家庄', '保定', '廊坊'],
    '上海': ['南京', '杭州', '苏州', '无锡'],
    '广州': ['深圳', '佛山', '东莞', '中山'],
    '深圳': ['广州', '东莞', '惠州', '佛山']
}

LOCAL_RAIL_DATA_PATHS = [
    # 动态扫描用，不再固定文件名
    os.path.join(os.path.dirname(__file__), 'data')
]

def load_local_rail_data() -> List[Dict]:
    """加载本地铁路数据，支持xlsx/csv。列要求：origin,destination,train_number,departure_time,arrival_time,price,transfer(optional)
    返回标准化字典列表。
    """
    data_dir = LOCAL_RAIL_DATA_PATHS[0]
    if not os.path.isdir(data_dir):
        print("❌ 数据目录不存在:", data_dir)
        return []
    try:
        import glob
        import pandas as pd
        files = glob.glob(os.path.join(data_dir, '*.xlsx')) + glob.glob(os.path.join(data_dir, '*.csv'))
        required_cols = {'origin','destination','train_number','price'}  # 时间列改为可选
        all_records: List[Dict] = []
        
        print(f"📂 扫描数据目录: {data_dir}")
        print(f"📋 找到文件: {[os.path.basename(f) for f in files]}")
        
        for path in files:
            try:
                print(f"📖 正在读取: {os.path.basename(path)}")
                
                if path.endswith('.xlsx'):
                    try:
                        # 检查文件大小，大文件给出提示
                        file_size = os.path.getsize(path)
                        if file_size > 50 * 1024 * 1024:  # 50MB以上
                            print(f"⚠️ 正在读取大文件 {os.path.basename(path)} ({file_size//1024//1024}MB)，请稍等...")
                        
                        # 先读取表头定位列
                        header_df = pd.read_excel(path, nrows=0, engine='openpyxl')
                        # 表头标准化
                        lower_cols_map = {str(c).strip().lower(): c for c in header_df.columns}
                        header_alias = {
                            'origin': ['origin','出发地','出发城市','始发地','始发站','出发站','起点站'],
                            'destination': ['destination','目的地','到达城市','到达站','终点站'],
                            'train_number': ['train_number','车次','车次号','列车号','列车编号'],
                            'departure_time': ['departure_time','出发时间','发车时间','开车时间','发时'],
                            'arrival_time': ['arrival_time','到达时间','到时'],
                            'price': ['price','票价','二等座','二等座票价','最低价','参考价'],
                            'transfer': ['transfer','中转','中转城市','换乘城市'],
                            'seat_type': ['席别','座别','座位','座位类型']
                        }
                        selected_cols = {}
                        for std, aliases in header_alias.items():
                            for alias in aliases:
                                key = alias.strip().lower()
                                if key in lower_cols_map:
                                    selected_cols[std] = lower_cols_map[key]
                                    break
                        
                        # 只检查必需列（不包括时间）
                        if not {'origin','destination','train_number','price'}.issubset(set(selected_cols.keys())):
                            print(f"❌ 必需列缺失，跳过: {os.path.basename(path)}")
                            continue
                        
                        # 仅读取需要的列，读取全部数据
                        use_cols = list(selected_cols.values())
                        if 'seat_type' in selected_cols:
                            use_cols.append(selected_cols['seat_type'])
                        
                        df = pd.read_excel(path, usecols=use_cols, engine='openpyxl')
                        print(f"✅ Excel读取成功: {len(df)} 行")
                        
                    except Exception as e:
                        print(f"❌ Excel读取失败: {e}")
                        continue
                else:
                    # 检查文件大小，大文件给出提示
                    file_size = os.path.getsize(path)
                    if file_size > 50 * 1024 * 1024:  # 50MB以上
                        print(f"⚠️ 正在读取大文件 {os.path.basename(path)} ({file_size//1024//1024}MB)，请稍等...")
                    
                    # 自适应CSV编码与分隔符
                    df = None
                    for enc in ['utf-8', 'utf-8-sig', 'gbk']:
                        try:
                            df = pd.read_csv(path, encoding=enc, engine='python', sep=None)
                            print(f"✅ CSV读取成功 {os.path.basename(path)} 编码: {enc} 行数: {len(df)}")
                            break
                        except Exception:
                            continue
                    if df is None:
                        print(f"❌ CSV读取失败: {os.path.basename(path)}")
                        continue
                
                # 表头标准化与中英映射
                col_map = {}
                for c in df.columns:
                    cl = str(c).strip().lower()
                    col_map[cl] = cl
                # 中文->标准名
                header_alias = {
                    'origin': ['origin','出发地','出发城市','始发地','始发站','出发站','起点站'],
                    'destination': ['destination','目的地','到达城市','到达站','终点站'],
                    'train_number': ['train_number','车次','车次号','列车号','列车编号'],
                    'departure_time': ['departure_time','出发时间','发车时间','开车时间','发时'],
                    'arrival_time': ['arrival_time','到达时间','到时'],
                    'price': ['price','票价','二等座','二等座票价','最低价','参考价'],
                    'transfer': ['transfer','中转','中转城市','换乘城市'],
                    'seat_type': ['席别','座别','座位','座位类型']
                }
                # 找出每个标准列在df中的真实列名
                selected_cols = {}
                lower_cols = {str(c).strip().lower(): c for c in df.columns}
                for std, aliases in header_alias.items():
                    for alias in aliases:
                        key = alias.strip().lower()
                        if key in lower_cols:
                            selected_cols[std] = lower_cols[key]
                            break
                
                # 只检查必需列（不包括时间）
                if not {'origin','destination','train_number','price'}.issubset(set(selected_cols.keys())):
                    print(f"❌ 必需列缺失，跳过: {os.path.basename(path)}")
                    continue
                
                added = 0
                for _, row in df.iterrows():
                    # 优先保留二等座票价
                    if 'seat_type' in selected_cols:
                        seat = str(row.get(selected_cols['seat_type'], '')).strip()
                        if seat and ('二等' not in seat) and ('硬座' not in seat):
                            continue
                    
                    # 处理时间信息，允许为空
                    dep_time = str(row.get(selected_cols.get('departure_time', ''), '')).strip()
                    arr_time = str(row.get(selected_cols.get('arrival_time', ''), '')).strip()
                    
                    # 清理无效时间值
                    if dep_time in ['nan', 'None', 'null', '']:
                        dep_time = ''
                    if arr_time in ['nan', 'None', 'null', '']:
                        arr_time = ''
                    
                    rec = {
                        'origin': str(row.get(selected_cols['origin'], '')).strip(),
                        'destination': str(row.get(selected_cols['destination'], '')).strip(),
                        'train_number': str(row.get(selected_cols['train_number'], '')).strip(),
                        'departure_time': dep_time,
                        'arrival_time': arr_time,
                        'price': float(row.get(selected_cols['price'], 0) or 0),
                        'transfer': ''
                    }
                    
                    # 可选 transfer 列
                    if 'transfer' in selected_cols:
                        val = row.get(selected_cols['transfer'], '')
                        rec['transfer'] = '' if (val is None or (hasattr(pd, 'isna') and pd.isna(val))) else str(val).strip()
                    
                    # 只保留有效数据
                    if rec['origin'] and rec['destination'] and rec['price'] > 0:
                        all_records.append(rec)
                        added += 1
                
                print(f"✅ 已加载铁路数据 {os.path.basename(path)}：{added} 条有效记录")
                
            except Exception as e:
                print(f"❌ 解析铁路文件失败 {os.path.basename(path)}: {e}")
                continue
        
        print(f" 本地铁路数据加载完成：{len(all_records)} 条")
        return all_records
    except Exception as e:
        print(f"❌ 扫描本地铁路目录失败: {e}")
    return []

_LOCAL_RAIL_CACHE = load_local_rail_data()

def _norm_city(name: str) -> str:
    if not name:
        return ''
    n = str(name).strip()
    # 去除常见后缀
    for suf in ['市', '站', '南站', '北站', '东站', '西站', '火车站', '高铁站']:
        n = n.replace(suf, '')
    return n

def find_train_routes(origin: str, destination: str, date: str) -> List[Dict]:
    """基于本地铁路表，返回直达或一次中转的高铁方案
    注意：高铁票价固定，不随日期变化，所以忽略日期参数进行搜索
    """
    routes: List[Dict] = []
    if not _LOCAL_RAIL_CACHE:
        print("❌ 本地铁路数据为空")
        return routes
    
    o = _norm_city(origin)
    d = _norm_city(destination)
    
    print(f" 搜索高铁路线: {origin}({o}) → {destination}({d})")
    print(f"   高铁票价固定，忽略日期限制，使用用户选择日期 {date} 进行显示")
    
    # 直达
    direct_count = 0
    for r in _LOCAL_RAIL_CACHE:
        ro = _norm_city(r['origin'])
        rd = _norm_city(r['destination'])
        if ro == o and rd == d and not r.get('transfer'):
            # 高铁数据中的时间（如07:00, 07:33）
            dep_time = r.get('departure_time', '').strip()
            arr_time = r.get('arrival_time', '').strip()
            
            # 如果时间格式正确，直接使用
            if dep_time and arr_time and dep_time != 'nan' and arr_time != 'nan':
                # 计算行程时间
                try:
                    from datetime import datetime as _dt
                    dep_dt = _dt.strptime(dep_time, '%H:%M')
                    arr_dt = _dt.strptime(arr_time, '%H:%M')
                    duration_hours = (arr_dt - dep_dt).total_seconds() / 3600
                    if duration_hours < 0:  # 跨天情况
                        duration_hours += 24
                    duration_hours = max(0.5, round(duration_hours, 1))
                except:
                    duration_hours = 4.0  # 默认4小时
            else:
                # 如果时间信息缺失，使用默认时间
                dep_time = "08:00"
                arr_time = "12:00"
                duration_hours = 4.0
            
            routes.append({
                'type': 'high_speed_rail',
                'origin': origin,
                'destination': destination,
                'dep_time': f"{date} {dep_time}",  # 使用用户选择的日期进行显示
                'arr_time': f"{date} {arr_time}",  # 使用用户选择的日期进行显示
                'price': int(r['price']),
                'total_time': duration_hours,
                'total_price': int(r['price']),
                'transfers': 0,
                'train_number': r['train_number'],
                'details': [{
                    'type': 'high_speed_rail',
                    'origin': origin,
                    'destination': destination,
                    'departure_time': dep_time,  # 只显示时间，不包含日期
                    'arrival_time': arr_time,    # 只显示时间，不包含日期
                    'price': int(r['price']),
                    'train_number': r['train_number']
                }]
            })
            direct_count += 1
    
    print(f"✅ 找到 {direct_count} 条直达高铁路线")
    
    # 一次中转（如经南京）
    transfer_count = 0
    for r in _LOCAL_RAIL_CACHE:
        ro = _norm_city(r['origin'])
        if ro == o and r.get('transfer'):
            mid = _norm_city(r['transfer'])
            # 找到中转-终点的段
            for r2 in _LOCAL_RAIL_CACHE:
                r2o = _norm_city(r2['origin'])
                r2d = _norm_city(r2['destination'])
                if r2o == mid and r2d == d and (not r2.get('transfer')):
                    # 处理第一段高铁时间
                    dep_time1 = r.get('departure_time', '').strip()
                    arr_time1 = r.get('arrival_time', '').strip()
                    if not dep_time1 or dep_time1 == 'nan':
                        dep_time1 = "08:00"
                    if not arr_time1 or arr_time1 == 'nan':
                        arr_time1 = "12:00"
                    
                    # 处理第二段高铁时间（中转后）
                    dep_time2 = r2.get('departure_time', '').strip()
                    arr_time2 = r2.get('arrival_time', '').strip()
                    if not dep_time2 or dep_time2 == 'nan':
                        dep_time2 = "13:00"  # 中转后1小时出发
                    if not arr_time2 or arr_time2 == 'nan':
                        arr_time2 = "17:00"
                    
                    total_price = int((r['price'] or 0) + (r2['price'] or 0))
                    total_time = 8.0  # 中转路线默认8小时
                    
                    routes.append({
                        'type': 'high_speed_rail',
                        'origin': origin,
                        'destination': destination,
                        'dep_time': f"{date} {dep_time1}",  # 使用用户选择的日期进行显示
                        'arr_time': f"{date} {arr_time2}",  # 使用用户选择的日期进行显示
                        'price': total_price,
                        'total_time': total_time,
                        'total_price': total_price,
                        'transfers': 1,
                        'transfer_station': mid,
                        'details': [
                            {
                                'type': 'high_speed_rail',
                                'origin': origin,
                                'destination': mid,
                                'departure_time': dep_time1,
                                'arrival_time': arr_time1,
                                'price': int(r['price'] or 0),
                                'train_number': r['train_number']
                            },
                            {
                                'type': 'high_speed_rail',
                                'origin': mid,
                                'destination': destination,
                                'departure_time': dep_time2,
                                'arrival_time': arr_time2,
                                'price': int(r2['price'] or 0),
                                'train_number': r2['train_number']
                            }
                        ]
                    })
                    transfer_count += 1
                    if transfer_count >= 3:  # 限制中转路线数量
                        break
            if transfer_count >= 3:
                break
    
    print(f"✅ 找到 {transfer_count} 条中转高铁路线")
    print(f"📊 总计找到 {len(routes)} 条高铁路线")
    
    return routes

def _parse_hours(dep: str, arr: str) -> float:
    try:
        if not dep or not arr:
            return 0.0
        from datetime import datetime as _dt
        d1 = _dt.strptime(dep.strip(), '%H:%M')
        d2 = _dt.strptime(arr.strip(), '%H:%M')
        delta = (d2 - d1).total_seconds() / 3600.0
        if delta < 0:
            delta += 24
        return round(max(0.0, delta), 1)
    except Exception:
        return 0.0

def build_flight_rail_combos(final_destination: str, date: str, flights: List[Dict]) -> List[Dict]:
    combos: List[Dict] = []
    if not _LOCAL_RAIL_CACHE:
        print("❌ 本地铁路数据为空，无法构建联运方案")
        return combos
    
    fd = _norm_city(final_destination)
    print(f" 开始构建联运方案: 目标城市 {final_destination}({fd})")
    print(f"   高铁票价固定，忽略日期限制，使用用户选择日期 {date} 进行显示")
    
    combo_count = 0
    for f in flights:
        try:
            # 只考虑"到附近城市"的航班作为联运的第一段
            if not f.get('is_nearby') or f.get('nearby_type') != 'destination':
                continue
            mid_city = f.get('nearby_city') or ''
            mid = _norm_city(mid_city)
            if not mid:
                continue
            
            # 解析航班到达时间
            flight_arr_time = f.get('arr_time', '')
            if not flight_arr_time:
                continue
                
            # 提取航班到达时间（HH:MM格式）
            try:
                # 从 "2025-09-24 12:00" 中提取 "12:00"
                flight_time_str = flight_arr_time.split(' ')[-1] if ' ' in flight_arr_time else flight_arr_time
                from datetime import datetime as _dt
                flight_arr_dt = _dt.strptime(flight_time_str, '%H:%M')
                
                # 计算最早可乘坐的高铁出发时间（航班落地 + 1小时缓冲）
                earliest_train_dep_dt = flight_arr_dt + timedelta(hours=1)
                earliest_train_dep_time = earliest_train_dep_dt.strftime('%H:%M')
                
                print(f"   搜索 {mid_city} → {final_destination} 的高铁...")
                print(f"     航班到达时间: {flight_time_str}")
                print(f"     最早高铁出发时间: {earliest_train_dep_time} (需1小时缓冲)")
                
            except Exception as e:
                print(f"  ❌ 解析航班时间失败: {e}")
                continue
            
            # 查询中转城市 -> 最终目的地 的直达高铁
            trains = find_train_routes(mid_city, final_destination, date)
            trains = [t for t in trains if t.get('transfers', 0) == 0 and t.get('type') == 'high_speed_rail']
            
            # 过滤符合时间要求的高铁
            valid_trains = []
            for t in trains:
                train_detail = t['details'][0] if t.get('details') else {}
                train_dep_time = train_detail.get('departure_time', '')
                
                if train_dep_time:
                    try:
                        train_dep_dt = _dt.strptime(train_dep_time, '%H:%M')
                        if train_dep_dt >= earliest_train_dep_dt:
                            valid_trains.append(t)
                            print(f"     ✅ 符合时间要求: {train_dep_time} (航班{flight_time_str}落地+1小时)")
                        else:
                            print(f"     ❌ 时间太早: {train_dep_time} (需要{earliest_train_dep_time}之后)")
                    except Exception as e:
                        print(f"     ❌ 解析高铁时间失败: {train_dep_time}")
                        continue
            
            if not valid_trains:
                print(f"     ❌ 没有符合时间要求的高铁")
                continue
            
            # 选一条价格最低的符合时间要求的高铁
            valid_trains.sort(key=lambda t: t.get('total_price', t.get('price', 0)))
            t = valid_trains[0]
            train_detail = t['details'][0] if t.get('details') else {}
            
            # 计算总价与总时间
            total_price = int((f.get('total_price') or f.get('price') or 0) + (t.get('total_price') or t.get('price') or 0))
            flight_time = f.get('total_time') or _parse_hours(str(f.get('dep_time',''))[-5:], str(f.get('arr_time',''))[-5:])
            train_time = t.get('total_time') or _parse_hours(train_detail.get('departure_time',''), train_detail.get('arrival_time',''))
            total_time = round((flight_time or 0) + (train_time or 0), 1)
            
            combos.append({
                'type': 'multimodal',
                'origin': f.get('origin'),
                'destination': final_destination,
                'dep_time': f.get('dep_time'),  # 航班时间（包含实际日期）
                'arr_time': t.get('arr_time'),  # 高铁到达时间（使用用户选择日期）
                'total_price': total_price,
                'total_time': total_time,
                'transfers': 1,
                'transfer_city': mid_city,
                'transfer_time': f"{flight_time_str} → {train_detail.get('departure_time','')} (缓冲1小时)",
                'details': [
                    {
                        'type': 'flight',
                        'origin': f.get('origin'),
                        'destination': mid_city,
                        'departure_time': str(f.get('dep_time',''))[-5:],  # 只显示时间
                        'arrival_time': str(f.get('arr_time',''))[-5:],    # 只显示时间
                        'price': int(f.get('total_price') or f.get('price') or 0),
                        'airline': f.get('airline'),
                        'flight_number': f.get('flight_number')
                    },
                    {
                        'type': 'high_speed_rail',
                        'origin': mid_city,
                        'destination': final_destination,
                        'departure_time': train_detail.get('departure_time',''),  # 只显示时间
                        'arrival_time': train_detail.get('arrival_time',''),      # 只显示时间
                        'price': int(t.get('total_price') or t.get('price') or 0),
                        'train_number': train_detail.get('train_number','')
                    }
                ]
            })
            combo_count += 1
            
        except Exception as e:
            print(f"  ❌ 构建联运失败: {e}")
            continue
    
    print(f"✅ 构建联运方案完成: {combo_count} 条")
    return combos

def http_get_with_retry(url, params, timeout_seconds=25, max_retries=2):
    session = requests.Session()
    last_exc = None
    for attempt in range(max_retries + 1):
        try:
            resp = session.get(url, params=params, timeout=timeout_seconds)
            return resp
        except Exception as e:
            last_exc = e
            backoff = 1.5 ** attempt
            print(f"⚠️ 航班API请求失败，第{attempt+1}次：{e}，{('重试中' if attempt < max_retries else '不再重试')}…")
            if attempt < max_retries:
                time.sleep(backoff)
    raise last_exc


def get_flight_data(origin, destination, date):
    """获取机票数据"""
    try:
        dep_code = CITY_TO_IATA.get(origin, origin)
        arr_code = CITY_TO_IATA.get(destination, destination)
        
        url = "https://apis.juhe.cn/flight/query"
        params = {
            'key': JUHE_FLIGHT_APPKEY,
            'dtype': 'json',
            'departure': dep_code,
            'arrival': arr_code,
            'departureDate': date
        }
        
        print(f"✈️ 获取机票数据: {origin}({dep_code}) → {destination}({arr_code})")
        
        try:
            response = http_get_with_retry(url, params=params, timeout_seconds=25, max_retries=2)
        except Exception as e:
            print(f"❌ 航班API连续失败: {e}")
            # 兜底：返回一条可用的示例航班，避免前端空白
            fallback = [{
                'type': 'flight',
                'flight_number': 'DEMO001',
                'airline': '示例航空',
                'origin': origin,
                'destination': destination,
                'dep_time': f"{date or ''} 09:00",
                'arr_time': f"{date or ''} 11:00",
                'price': 680,
                'dep_airport': f"{origin}机场",
                'arr_airport': f"{destination}机场",
                'duration': '09:00 - 11:00',
                'source': 'fallback',
                'crawl_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                'total_time': 2.0,
                'total_price': 680,
                'transfers': 0,
                'details': [{
                    'type': 'flight', 'origin': origin, 'destination': destination,
                    'departure_time': '09:00', 'arrival_time': '11:00', 'price': 680
                }]
            }]
            return fallback
        
        if response.status_code == 200:
            result = response.json()
            
            if result.get('error_code') == 0:
                flights = []
                flight_list = result.get('result', {}).get('flightInfo', [])
                
                for item in flight_list:
                    try:
                        # 计算总时间（小时）
                        dep_time = item.get('departureTime', '')
                        arr_time = item.get('arrivalTime', '')
                        dep_date = item.get('departureDate', '')
                        arr_date = item.get('arrivalDate', '')
                        total_time = 2.0  # 默认2小时
                        try:
                            # 组装完整时间，例如 2025-09-20 07:30
                            dep_dt_str = f"{dep_date} {dep_time}".strip()
                            arr_dt_str = f"{arr_date} {arr_time}".strip()
                            from datetime import datetime as _dt
                            dep_dt = _dt.strptime(dep_dt_str, '%Y-%m-%d %H:%M')
                            arr_dt = _dt.strptime(arr_dt_str, '%Y-%m-%d %H:%M')
                            # 计算相差分钟（处理跨天）
                            if arr_dt < dep_dt:
                                # 少数数据可能日期未对齐，强制加一天
                                arr_dt = arr_dt.replace(day=arr_dt.day) + timedelta(days=1)
                            total_minutes = int((arr_dt - dep_dt).total_seconds() // 60)
                            total_time = max(0.5, round(total_minutes / 60.0, 1))
                        except Exception:
                            pass
                        
                        flight = {
                            'type': 'flight',
                            'flight_number': item.get('flightNo', ''),
                            'airline': item.get('airlineName', ''),
                            'origin': origin,
                            'destination': destination,
                            'dep_time': f"{item.get('departureDate', '')} {item.get('departureTime', '')}",
                            'arr_time': f"{item.get('arrivalDate', '')} {item.get('arrivalTime', '')}",
                            'price': int(item.get('ticketPrice', 0)),
                            'dep_airport': item.get('departureName', ''),
                            'arr_airport': item.get('arrivalName', ''),
                            'duration': f"{item.get('departureTime', '')} - {item.get('arrivalTime', '')}",
                            'source': '聚合数据API',
                            'crawl_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                            # 前端期望字段
                            'total_time': total_time,
                            'total_price': int(item.get('ticketPrice', 0)),
                            'transfers': 0,
                            'details': [{
                                'type': 'flight',
                                'origin': origin,
                                'destination': destination,
                                'departure_time': f"{item.get('departureTime', '')}",
                                'arrival_time': f"{item.get('arrivalTime', '')}",
                                'price': int(item.get('ticketPrice', 0)),
                                'airline': item.get('airlineName', ''),
                                'flight_number': item.get('flightNo', '')
                            }]
                        }
                        
                        if flight['price'] > 0:
                            flights.append(flight)
                            
                    except Exception as e:
                        print(f"  ❌ 解析航班条目异常: {e}")
                        continue
                
                print(f"✅ 获取到 {len(flights)} 条机票数据")
                return flights
            else:
                print(f"❌ 机票API错误: {result.get('reason', '未知')}")
                return []
        else:
            print(f"❌ 机票API请求失败: {response.status_code}")
            return []
            
    except Exception as e:
        print(f"❌ 机票API异常: {e}")
        return []

class MyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
    def __init__(self, *args, **kwargs):
        static_root = os.path.dirname(__file__)
        super().__init__(*args, directory=static_root, **kwargs)
    
    def do_OPTIONS(self):
        # 处理CORS预检
        self.send_response(200)
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
        self.send_header('Access-Control-Allow-Headers', 'Content-Type')
        self.end_headers()
    
    def do_GET(self):
        if self.path == '/':
            self.path = '/frontend/index.html'
        elif self.path.startswith('/api/'):
            self.handle_api_request()
            return
        super().do_GET()
    
    def do_POST(self):
        if self.path == '/api/search':
            self.handle_search_request()
        elif self.path == '/api/poi':
            self.handle_poi_request()
        elif self.path == '/api/geocode':
            self.handle_geocode_request()
        elif self.path == '/api/chat':
            self.handle_chat_request()
        else:
            self.send_error(404)
    
    def handle_api_request(self):
        if self.path == '/api/status':
            self.send_api_status()
        elif self.path == '/api/cities':
            self.send_cities()
        elif self.path.startswith('/api/weather'):
            self.send_weather()
        else:
            self.send_error(404)
    
    def handle_search_request(self):
        content_length = int(self.headers.get('Content-Length', 0))
        post_data = self.rfile.read(content_length)
        
        try:
            data = json.loads(post_data.decode('utf-8'))
        except:
            data = {}
        
        origin = data.get('origin', '北京')
        destination = data.get('destination', '上海')
        date = data.get('date') or data.get('departure_date')
        optimization_type = data.get('optimization_type', 'time')
        
        print(f"\n🔍 搜索请求: {origin} → {destination} ({date})")
        print("=" * 50)
        
        all_routes = []
        
        # 获取机票数据
        print("✈️ 获取机票数据...")
        flights = get_flight_data(origin, destination, date or '2025-09-20')
        all_routes.extend(flights)
        print(f"   机票: {len(flights)} 条")

        # 获取高铁数据
        print("🚂 获取高铁数据...")
        print(f"   本地缓存数据量: {len(_LOCAL_RAIL_CACHE)} 条")
        try:
            rail_routes = find_train_routes(origin, destination, date or '2025-09-20')
            all_routes.extend(rail_routes)
            print(f"   高铁: {len(rail_routes)} 条")
        except Exception as e:
            print(f"❌ 读取本地铁路数据失败: {e}")

        # 周边城市数据
        print("🌍 获取周边城市数据...")
        nearby_origins = NEARBY_CITIES.get(origin, [])
        nearby_destinations = NEARBY_CITIES.get(destination, [])
        
        nearby_count = 0
        # 周边出发城市
        for nearby_origin in nearby_origins[:2]:
            if nearby_origin not in CITY_TO_IATA:
                continue
            nearby_flights = get_flight_data(nearby_origin, destination, date or '2025-09-20')
            for flight in nearby_flights:
                flight['is_nearby'] = True
                flight['nearby_type'] = 'origin'
                flight['nearby_city'] = nearby_origin
                flight['origin'] = f"{nearby_origin}({origin}附近)"
            all_routes.extend(nearby_flights)
            nearby_count += len(nearby_flights)
        
        # 周边到达城市
        for nearby_dest in nearby_destinations[:2]:
            if nearby_dest not in CITY_TO_IATA:
                continue
            nearby_flights = get_flight_data(origin, nearby_dest, date or '2025-09-20')
            for flight in nearby_flights:
                flight['is_nearby'] = True
                flight['nearby_type'] = 'destination'
                flight['nearby_city'] = nearby_dest
                flight['destination'] = f"{nearby_dest}({destination}附近)"
            all_routes.extend(nearby_flights)
            nearby_count += len(nearby_flights)
        
        print(f"   周边城市: {nearby_count} 条")

        # 航班+高铁 联运方案（航班到附近城市 + 高铁至终点）
        print("🚀 开始构建多式联运方案...")
        try:
            intermodal = build_flight_rail_combos(destination, date or '2025-09-20', all_routes)
            all_routes.extend(intermodal)
            print(f"   联运: {len(intermodal)} 条")
        except Exception as e:
            print(f"❌ 联运构建失败: {e}")

        # 使用增强的排序逻辑
        print("🧠 开始智能排序...")
        all_routes = enhanced_sort_routes(all_routes, optimization_type)
        
        # 统计信息
        flights_count = len([x for x in all_routes if x.get('type') == 'flight'])
        trains_count = len([x for x in all_routes if x.get('type') == 'high_speed_rail'])
        multimodal_count = len([x for x in all_routes if x.get('type') == 'multimodal'])
        nearby_count = len([x for x in all_routes if x.get('is_nearby', False)])
        
        # 按到达类型统计
        same_day_count = len([x for x in all_routes if x.get('arrival_type') == 'same_day'])
        next_day_count = len([x for x in all_routes if x.get('arrival_type') == 'next_day'])
        
        result = {
            'success': True,
            'routes': all_routes,
            'data': all_routes,
            'total': len(all_routes),
            'flights': flights_count,
            'trains': trains_count,
            'multimodal': multimodal_count,
            'nearby': nearby_count,
            'same_day': same_day_count,
            'next_day': next_day_count,
            'optimization_type': optimization_type,
            'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        }
        
        print(f"✅ 搜索完成: 总计 {len(all_routes)} 条结果")
        print(f"   ✈️ 机票: {flights_count} 条")
        print(f"   高铁: {trains_count} 条")
        print(f"   联运: {multimodal_count} 条")
        print(f"   �� 周边: {nearby_count} 条")
        print(f"   日内到达: {same_day_count} 条")
        print(f"   隔日到达: {next_day_count} 条")
        print("=" * 50)
        
        self.send_json_response(result)
    
    def send_api_status(self):
        status = {
            'success': True,
            'status': 'success',
            'message': '最终版服务器运行正常',
            'version': '6.0.0',
            'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            'features': [
                '真实机票数据获取（聚合数据API）',
                '本地高铁数据读取（完整版）',
                '多式联运智能规划（时间衔接）',
                '周边城市智能对比',
                '智能排序和推荐'
            ],
            'apis': {
                'flight': 'enabled',
                'railway': 'enabled',
                'multimodal': 'enabled',
                'nearby': 'enabled',
                'smart_sort': 'enabled',
                'weather': 'mock',
                'poi': 'mock',
                'geocode': 'mock',
                'chat': 'mock'
            },
            'nearby_cities': NEARBY_CITIES,
            'railway_data_count': len(_LOCAL_RAIL_CACHE)
        }
        self.send_json_response(status)
    
    def send_cities(self):
        cities = list(NEARBY_CITIES.keys())
        self.send_json_response({'success': True, 'cities': cities})
    
    def send_weather(self):
        # 读取查询参数
        try:
            from urllib.parse import urlparse, parse_qs
            query = parse_qs(urlparse(self.path).query)
            city = (query.get('city') or ['北京'])[0]
        except Exception:
            city = '北京'
        # 返回轻量模拟数据（前端已有容错逻辑）
        data = {
            'success': True,
            'weather': {
                'weather': '晴',
                'temperature': 22,
                'humidity': 60,
                'wind_power': 3,
                'wind_direction': '东南风'
            },
            'city': city,
            'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        }
        self.send_json_response(data)
    
    def handle_poi_request(self):
        content_length = int(self.headers.get('Content-Length', 0))
        body = self.rfile.read(content_length) if content_length > 0 else b'{}'
        try:
            payload = json.loads(body.decode('utf-8'))
        except:
            payload = {}
        keyword = payload.get('keyword', '景点')
        city = payload.get('city', '北京')
        # 轻量模拟POI结果
        pois = [
            { 'id': '1', 'name': f'{city}{keyword}示例一', 'address': f'{city}中心区', 'location': '116.3974,39.9093', 'type': keyword },
            { 'id': '2', 'name': f'{city}{keyword}示例二', 'address': f'{city}热门商圈', 'location': '116.4053,39.9042', 'type': keyword },
            { 'id': '3', 'name': f'{city}{keyword}示例三', 'address': f'{city}特色街区', 'location': '116.4120,39.9200', 'type': keyword }
        ]
        self.send_json_response({ 'success': True, 'pois': pois })
    
    def handle_geocode_request(self):
        content_length = int(self.headers.get('Content-Length', 0))
        body = self.rfile.read(content_length) if content_length > 0 else b'{}'
        try:
            payload = json.loads(body.decode('utf-8'))
        except:
            payload = {}
        address = payload.get('address', '北京市东城区天安门')
        # 轻量模拟坐标（固定到天安门附近）
        coordinates = { 'lng': 116.3974, 'lat': 39.9093 }
        self.send_json_response({ 'success': True, 'address': address, 'coordinates': coordinates })
    
    def handle_chat_request(self):
        content_length = int(self.headers.get('Content-Length', 0))
        body = self.rfile.read(content_length) if content_length > 0 else b'{}'
        try:
            payload = json.loads(body.decode('utf-8'))
        except:
            payload = {}
        message = payload.get('message', '')
        # 非AI的简单回声/提示（前端已有意图识别与容错）
        reply = f"已收到：{message}。您也可以直接输入'北京到上海'或'查询北京天气'等指令哦。"
        self.send_json_response({ 'success': True, 'response': reply })
    
    def send_json_response(self, data):
        self.send_response(200)
        self.send_header('Content-type', 'application/json; charset=utf-8')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
        self.send_header('Access-Control-Allow-Headers', 'Content-Type')
        self.end_headers()
        
        json_data = json.dumps(data, ensure_ascii=False, indent=2)
        self.wfile.write(json_data.encode('utf-8'))

def calculate_arrival_type(route: Dict) -> str:
    """计算路线类型：日内到达或隔日到达"""
    try:
        dep_time = route.get('dep_time', '')
        arr_time = route.get('arr_time', '')
        
        if not dep_time or not arr_time:
            return 'unknown'
        
        # 提取时间部分
        dep_time_str = dep_time.split(' ')[-1] if ' ' in dep_time else dep_time
        arr_time_str = arr_time.split(' ')[-1] if ' ' in arr_time else arr_time
        
        from datetime import datetime as _dt
        dep_dt = _dt.strptime(dep_time_str, '%H:%M')
        arr_dt = _dt.strptime(arr_time_str, '%H:%M')
        
        # 如果到达时间早于出发时间，说明是隔日到达
        if arr_dt < dep_dt:
            return 'next_day'
        else:
            return 'same_day'
            
    except Exception:
        return 'unknown'

def enhanced_sort_routes(routes: List[Dict], optimization_type: str) -> List[Dict]:
    """增强的路线排序：优先日内到达，然后按用户选择排序"""
    
    # 为每条路线添加到达类型标签
    for route in routes:
        route['arrival_type'] = calculate_arrival_type(route)
    
    # 分离日内到达和隔日到达
    same_day_routes = [r for r in routes if r['arrival_type'] == 'same_day']
    next_day_routes = [r for r in routes if r['arrival_type'] == 'next_day']
    unknown_routes = [r for r in routes if r['arrival_type'] == 'unknown']
    
    print(f"📊 路线分类统计:")
    print(f"   日内到达: {len(same_day_routes)} 条")
    print(f"   隔日到达: {len(next_day_routes)} 条")
    print(f"   未知类型: {len(unknown_routes)} 条")
    
    # 对日内到达路线按用户选择排序
    if optimization_type == 'price':
        same_day_routes.sort(key=lambda x: x.get('total_price') if x.get('total_price') is not None else x.get('price', 0))
    elif optimization_type == 'time':
        same_day_routes.sort(key=lambda x: x.get('total_time', 0))
    
    # 对隔日到达路线按用户选择排序
    if optimization_type == 'price':
        next_day_routes.sort(key=lambda x: x.get('total_price') if x.get('total_price') is not None else x.get('price', 0))
    elif optimization_type == 'time':
        next_day_routes.sort(key=lambda x: x.get('total_time', 0))
    
    # 对未知类型路线按用户选择排序
    if optimization_type == 'price':
        unknown_routes.sort(key=lambda x: x.get('total_price') if x.get('total_price') is not None else x.get('price', 0))
    elif optimization_type == 'time':
        unknown_routes.sort(key=lambda x: x.get('total_time', 0))
    
    # 合并结果：日内到达优先，然后隔日到达，最后未知类型
    final_routes = same_day_routes + next_day_routes + unknown_routes
    
    # 为路线添加标签
    for i, route in enumerate(final_routes):
        if route['arrival_type'] == 'same_day':
            route['arrival_label'] = '日内到达'
            route['priority'] = 1
        elif route['arrival_type'] == 'next_day':
            route['arrival_label'] = '隔日到达'
            route['priority'] = 2
        else:
            route['arrival_label'] = '未知'
            route['priority'] = 3
        
        # 添加排序说明
        if i < len(same_day_routes):
            route['sort_info'] = f"日内到达-{optimization_type}优先"
        elif i < len(same_day_routes) + len(next_day_routes):
            route['sort_info'] = f"隔日到达-{optimization_type}优先"
        else:
            route['sort_info'] = f"未知类型-{optimization_type}优先"
    
    return final_routes

if __name__ == '__main__':
    PORT = 5000
    
    print("=" * 60)
    print(" 启动最终版HTTP服务器")
    print("=" * 60)
    print(f"服务地址: http://localhost:{PORT}")
    print(f"前端页面: http://localhost:{PORT}/frontend/index.html")
    print(f"本地高铁数据: {len(_LOCAL_RAIL_CACHE)} 条")
    print("=" * 60)
    print("按 Ctrl+C 停止服务")
    print("=" * 60)
    
    try:
        # 自动打开浏览器到前端页面
        try:
            webbrowser.open(f"http://localhost:{PORT}/frontend/index.html")
        except Exception:
            pass
        with socketserver.TCPServer(("", PORT), MyHTTPRequestHandler) as httpd:
            httpd.serve_forever()
    except KeyboardInterrupt:
        print("\n服务器已停止")
    except Exception as e:
        print(f"服务器启动失败: {e}")
